" ===
" === Auto load for first time uses
" ===
if empty(glob($HOME.'/.config/nvim/autoload/plug.vim'))
	silent !curl -fLo $HOME/.config/nvim/autoload/plug.vim --create-dirs
				\ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
	autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif

" ====================
" === Editor Setup ===
" ====================
" ===
" === System
" ===
"set clipboard=unnamedplus
" 使配色更加兼容你的终端
let &t_ut=''
" 自动切换工作目录到当前文件的目录下
set autochdir
" 插件兼容
set nocompatible
filetype on
filetype indent on
filetype plugin on
filetype plugin indent on
set encoding=utf-8

" ===
" === Editor behavior
" ===
" 会加载项目目录下的配置文件
set exrc
" 禁用项目目录下的配置文件使用 shell autocmd write 等命令
set secure
" 显示行数
set number
" 显示相对行数
set relativenumber
" 高亮当前行
set cursorline
" 高亮当前列
" set cursorcolumn
" 允许隐藏缓存区--允许修改一个文件后，不保存修改就可以编辑查看另一个文件
set hidden

" 自动缩进
set autoindent
" 智能缩进：对 autoindent 进行了一些改进，可以识别一些基本的语法
set smartindent
" 按照 C 语言的语法，自动调整缩进的长度
set cindent
" 得到一行的缩进位置的表达式
" set indentexpr=
" 不使用空格来替换 TAB
set noexpandtab
" 定义 TAB 所等同的空格长度
set tabstop=4
" 自动缩进使用的的空格长度
set shiftwidth=4
" 当按下 TAB 键，插入的是空格和 TAB 制表符的混合
" softtabstop 长度等于 4，插入的就是一个正常的制表符
" softtabstop 长度不等于 4，插入的就是制表符和空格的混合，
" 当空格长度达到 4 格时，就会被整体替换成一个制表符
set softtabstop=4
" 显示 TAB、空格、回车等不可见字符
set list
" 设置不可见字符的显示方式
set listchars=tab:\|\ ,trail:▫

" 在滚动屏幕浏览的时候，在光标的上方和下方保持可见的行数
set scrolloff=5
" 关闭键码延时
set ttimeoutlen=0
" 关闭映射延时
" set timeoutlen=0
set notimeout
" 长行回绕并在下一行继续
set wrap

" 启用折叠
set foldenable
" 按照缩进折叠
set foldmethod=indent
" 设置折叠级别: 高于此级别的折叠会被关闭
" 99 打开文件时，默认都不折叠
" 0 打开文件时，默认都折叠
set foldlevel=99
" 指定 :mkview 保存的内容
" set viewoptions=cursor,folds,slash,unix

" 关闭默认输入超过 78 个字符时自动换行功能
" 插入文本的最大宽度 tw == textwidth
set tw=0
" 描述自动排版如何进行的字母序列，参考 :help fo-table
set formatoptions-=tc

" 新分割的窗口放到当前窗口的右下方
set splitright
set splitbelow
" 不在状态行上显示当前模式的消息
set noshowmode
" 在状态行里显示 (部分) 命令
set showcmd
" 打开时，命令行补全以增强模式运行，显示候选菜单
set wildmenu
" 搜索模式时忽略大小写
set ignorecase
" 搜索模式中有大写字母时不忽略大小写
set smartcase
" 缩短消息长度的标志位列表
" set shortmess+=c
" 搜索高亮
set hlsearch
" 因为每次加载新的 vim 时可能还会显示上一次的搜索高亮，exec 是运行后面的指令，
" 就是执行一次没有搜索高亮，就可以解决这个问题了。
exec "nohlsearch"
" 边搜索边高亮
set incsearch
" 能即时预览命令的效果（目前只支持:s替换）
" split 命令的更改会在 preview 中显示
" nosplit 命令更改会在原位置显示
set inccommand=split
" 插入模式补全使用的选项
set completeopt=longest,noinsert,menuone,noselect,preview

" 优化滚动速度
" 表明使用的是快速终端连接
set ttyfast
" 如果置位本选项，执行宏、寄存器和其它不通过输入的命令时屏幕不会重画。另
" 外，窗口标题的刷新也被推迟。要强迫刷新，使用  :redraw 。
set lazyredraw

" 使用可视响铃代替鸣叫
set visualbell
silent !mkdir -p $HOME/.config/nvim/tmp/backup
silent !mkdir -p $HOME/.config/nvim/tmp/undo
"silent !mkdir -p $HOME/.config/nvim/tmp/sessions
" 备份文件和交换文件存放路径
set backupdir=$HOME/.config/nvim/tmp/backup,.
set directory=$HOME/.config/nvim/tmp/backup,.
" 撤销文件使用的目录名列表，以逗号分隔
if has('persistent_undo')
	set undofile
	set undodir=$HOME/.config/nvim/tmp/undo,.
endif
" 在哪些列显示一个标尺，标示输入接近多少个字符
set colorcolumn=100
" 更改 ColorColumn 颜色，默认红色
" highlight ColorColumn ctermbg=0 guibg=lightgrey
" 如果过了这么多毫秒数以后还没有任何输入，
" 把交换文件写入磁盘（从崩溃中恢复）
set updatetime=100
" 允许可视列块模式的虚拟编辑
" 虚拟编辑意味着光标可以定位在没有实际字符的地方。这可以是制表的中间，
" 也可以是行尾之后的位置。可用于在可视模式下选择一个方块，还有表格的编辑。
set virtualedit=block

" 让 vim 记忆上次编辑的位置
au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif

" ===
" === Basic Mappings
" ===
" Set <LEADER> as <SPACE>, ; as :
let mapleader=" "
" noremap ; :

" Save & quit
noremap Q :q<CR>
" noremap <C-q> :qa<CR>
noremap S :w<CR>

" Open the vimrc file anytime
noremap <LEADER>rc :e $HOME/.config/nvim/init.vim<CR>
noremap <LEADER>rv :e .nvimrc<CR>

" make Y to copy till the end of the line
nnoremap Y y$

" Copy to system clipboard
vnoremap Y "+y

" Disable the default s key
noremap s <nop>

" split the screens to up (horizontal), down (horizontal), left (vertical), right (vertical)
noremap sk :set nosplitbelow<CR>:split<CR>:set splitbelow<CR>
noremap sj :set splitbelow<CR>:split<CR>
noremap sh :set nosplitright<CR>:vsplit<CR>:set splitright<CR>
noremap sl :set splitright<CR>:vsplit<CR>

" Resize splits with arrow keys
noremap <LEADER><up> :res +5<CR>
noremap <LEADER><down> :res -5<CR>
noremap <LEADER><left> :vertical resize-5<CR>
noremap <LEADER><right> :vertical resize+5<CR>

" ===
" === Tab management
" ===
" Create a new tab with tu
noremap tu :tabe<CR>
noremap tU :tab split<CR>
" Move around tabs with tn and ti
noremap tn :-tabnext<CR>
noremap ti :+tabnext<CR>
" Move the tabs with tmn and tmi
noremap tmn :-tabmove<CR>
noremap tmi :+tabmove<CR>

" Press space twice to jump to the next '<++>' and edit it
noremap <LEADER><LEADER> <Esc>/<++><CR>:nohlsearch<CR>c4l

" Spelling Check with <space>sc
noremap <LEADER>sc :set spell!<CR>

" set wrap
noremap <LEADER>sw :set wrap!<CR>

" ===
" === Install Plugins with Vim-Plug
" ===
call plug#begin('$HOME/.config/nvim/plugged')
" Undo Tree
Plug 'mbbill/undotree'

" 启动页
Plug 'mhinz/vim-startify'

" 美化状态栏
Plug 'vim-airline/vim-airline'

" 配色
Plug 'connorholyday/vim-snazzy'

" File navigation
Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' }
Plug 'Xuyuanp/nerdtree-git-plugin'

" Taglist
Plug 'majutsushi/tagbar', { 'on': 'TagbarOpenAutoClose' }

" Other visual enhancement
Plug 'nathanaelkane/vim-indent-guides'
Plug 'itchyny/vim-cursorword'

" Git
" 解 git 冲突插件
" 跳转快捷键：[x and ]x
" 合并快捷键：ct for theirs, co for ours, cn for none and cb for both
Plug 'rhysd/conflict-marker.vim'
" vim 下的增强 git
Plug 'tpope/vim-fugitive'
" 在窗口的最右侧，添加一列用符号显示版本控制系统下的文件状态
Plug 'mhinz/vim-signify'

" <leader>cc   加注释
" <leader>cu   解开注释
" <leader>c<space>  加上/解开注释, 智能判断
" <leader>cy   先复制, 再注解(p可以进行黏贴)
Plug 'scrooloose/nerdcommenter' " in <space>cc to comment a line

" Markdown
Plug 'suan/vim-instant-markdown', {'for': 'markdown','do':'yarn install'}
Plug 'dhruvasagar/vim-table-mode', { 'on': 'TableModeToggle', 'for': ['text', 'markdown', 'vim-plug'] }
Plug 'mzlogin/vim-markdown-toc', { 'for': ['gitignore', 'markdown', 'vim-plug'] }
Plug 'dkarter/bullets.vim'

" For general writing
Plug 'junegunn/goyo.vim'

" For fuzzy file
Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all'  }
Plug 'junegunn/fzf.vim'

" For coc
Plug 'neoclide/coc.nvim', {'branch': 'release'}

" For Syntax files for bp, rc, aidl, and hal files.
Plug 'kheaactua/aosp-vim-syntax'

Plug 'gcmt/wildfire.vim'
Plug 'tpope/vim-surround'
Plug 'brooth/far.vim'
Plug 'godlygeek/tabular'
Plug 'easymotion/vim-easymotion'
Plug 'mg979/vim-visual-multi'

call plug#end()

" ===
" === vim-instant-markdown
" ===
let g:instant_markdown_slow = 0
let g:instant_markdown_autostart = 0
" let g:instant_markdown_open_to_the_world = 1
" let g:instant_markdown_allow_unsafe_content = 1
" let g:instant_markdown_allow_external_content = 0
" let g:instant_markdown_mathjax = 1
let g:instant_markdown_autoscroll = 1

" ===
" === vim-table-mode
" ===
noremap <LEADER>tm :TableModeToggle<CR>
"let g:table_mode_disable_mappings = 1
let g:table_mode_cell_text_object_i_map = 'k<Bar>'

" ===
" === Undotree
" ===
noremap L :UndotreeToggle<CR>
let g:undotree_DiffAutoOpen = 1
let g:undotree_SetFocusWhenToggle = 1
let g:undotree_ShortIndicators = 1
let g:undotree_WindowLayout = 2
let g:undotree_DiffpanelHeight = 8
let g:undotree_SplitWidth = 24
function g:Undotree_CustomMap()
	nmap <buffer> u <plug>UndotreeNextState
	nmap <buffer> e <plug>UndotreePreviousState
	nmap <buffer> U 5<plug>UndotreeNextState
	nmap <buffer> E 5<plug>UndotreePreviousState
endfunc

" === Bullets.vim
" ===
" let g:bullets_set_mappings = 0
let g:bullets_enabled_file_types = [
			\ 'markdown',
			\ 'text',
			\ 'gitcommit',
			\ 'scratch'
			\]

" ===
" === goyo
" ===
map <LEADER>gy :Goyo<CR>

" ===
" === startify
" ===
let g:startify_custom_header =
            \ startify#center(split(system('figlet -w 100 FDEBAD'), '\n'))

" ===
" === 配色设置
" ===
set background=dark
syntax enable
colorscheme snazzy

" ===
" === NERDTree
" ===
map tt :NERDTreeToggle<CR>

" ===
" === Nerdcommenter
" ===
" 注释的时候自动加个空格, 强迫症必配
let g:NERDSpaceDelims=1

" ==
" == NERDTree-git
" ==
let g:NERDTreeIndicatorMapCustom = {
    \ "Modified"  : "M",
    \ "Staged"    : "S",
    \ "Untracked" : "UT",
    \ "Renamed"   : "R",
    \ "Unmerged"  : "UM",
    \ "Deleted"   : "D",
    \ "Dirty"     : "✗",
    \ "Clean"     : "✔︎",
    \ "Unknown"   : "?"
    \ }

" ===
" === Taglist
" ===
map <silent> T :TagbarOpenAutoClose<CR>

" ===
" === vim-indent-guide
" ===
let g:indent_guides_guide_size = 1
let g:indent_guides_start_level = 2
let g:indent_guides_enable_on_vim_startup = 1
let g:indent_guides_color_change_percent = 1
silent! unmap <LEADER>ig
autocmd WinEnter * silent! unmap <LEADER>ig

" ===
" === coc
" ===
let g:coc_global_extensions = [
	\ 'coc-docker',
	\ 'coc-java',
	\ 'coc-json',
	\ 'coc-clangd',
	\ 'coc-sh',
	\ 'coc-pyright',
	\ 'coc-sh',
	\ 'coc-sql',
	\ 'coc-translator',
	\ 'coc-snippets',
	\ 'coc-eslint',
	\ 'coc-lists',
	\ 'coc-perl',
	\ 'coc-xml',
	\ 'coc-clang-format-style-options',
	\ 'coc-cmake',
	\ 'coc-diagnostic',
	\ 'coc-rainbow-fart',
	\ 'coc-vimlsp']
" Use tab for trigger completion with characters ahead and navigate.
" NOTE: Use command ':verbose imap <tab>' to make sure tab is not mapped by
" other plugin before putting this into your config.
inoremap <silent><expr> <TAB>
      \ pumvisible() ? "\<C-n>" :
      \ <SID>check_back_space() ? "\<TAB>" :
      \ coc#refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"

function! s:check_back_space() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~# '\s'
endfunction

" Use <c-h> to trigger completion.
inoremap <silent><expr> <c-h> coc#refresh()

" Make <CR> auto-select the first completion item and notify coc.nvim to
" format on enter, <cr> could be remapped by other vim plugin
inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm()
                              \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"

" Use `[g` and `]g` to navigate diagnostics
" Use `:CocDiagnostics` to get all diagnostics of current buffer in location list.
nmap <silent> [g <Plug>(coc-diagnostic-prev)
nmap <silent> ]g <Plug>(coc-diagnostic-next)

" GoTo code navigation.
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)

" Use K to show documentation in preview window.
nnoremap <silent> K :call <SID>show_documentation()<CR>

function! s:show_documentation()
  if (index(['vim','help'], &filetype) >= 0)
    execute 'h '.expand('<cword>')
  elseif (coc#rpc#ready())
    call CocActionAsync('doHover')
  else
    execute '!' . &keywordprg . " " . expand('<cword>')
  endif
endfunction

" Highlight the symbol and its references when holding the cursor.
autocmd CursorHold * silent call CocActionAsync('highlight')

" Symbol renaming.
nmap <leader>rn <Plug>(coc-rename)

" Formatting selected code.
xmap <leader>f  <Plug>(coc-format-selected)
nmap <leader>f  <Plug>(coc-format-selected)

augroup mygroup
  autocmd!
  " Setup formatexpr specified filetype(s).
  autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected')
  " Update signature help on jump placeholder.
  autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
augroup end
